home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
UTILITIE
/
CPU_MEMO
/
3468.ZIP
/
POPUP.ZIP
/
CLINK.INC
< prev
next >
Wrap
Text File
|
1988-06-30
|
9KB
|
328 lines
; CLINK.INC C to ASM macros.
; ---------
; Contains several macros which are useful when writing memory-model
; independant assembler functions to be called from 'C' functions.
; All the macros assume the the standard sequence of:
;
; push bp
; mov bp, sp
;
; will take place at the beginning of the assembler function. This is
; NOT necessary if the function has no arguments.
;
; The default memory-model is SMALL.
; To assemble for another memory model, define the memory model on
; the command line by MASM /D[ModelName] ...
; Where [ModelName] is SMALL, COMPACT, MEDIUM, LARGE or HUGE.
;
; Alternatively, you can define the memory mode within the program
; itself by doing: [ModelName] = 1
; This MUST be done before including CLINK.INC
;
; FURTHER NOTE : Whenever a register or segreg is specified, you must
; ALWAYS use lower case. (this applies to macros only!)
;
; Finally : If you are using MASM version 4.0 or before, then you
; will have to remove the .MODEL directive somewhere below. In that
; case, you will also have to specify the segments that are to be used.
; They are usually set out as follows:
;
;_TEXT SEGMENT BYTE PUBLIC 'CODE'
;_TEXT ENDS
;CONST SEGMENT WORD PUBLIC 'CONST'
;CONST ENDS
;_BSS SEGMENT WORD PUBLIC 'BSS'
;_BSS ENDS
;_DATA SEGMENT WORD PUBLIC 'DATA'
;_DATA ENDS
;DGROUP GROUP CONST, _BSS, _DATA
; ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP, ES: DGROUP
;
; NOTE : For LARGE CODE, then the _TEXT segment must be given a unique name.
; By convention, if the name of the module is "MOD", then the text segment
; would be declared as "MOD_TEXT". Easy really. Don't forget that the
; ASSUME reference to _TEXT would also have to be MOD_TEXT
;
; The above segments should be declared at the beginning of your assembler
; program, after including CLINK.INC, but ONLY for MASM 4.0 and earlier.
;
FALSE = 0
TRUE = 1
MODEL_NAME EQU <SMALL>
ifdef COMPACT
LARGE_DATA = 1
MODEL_NAME EQU <COMPACT>
endif
ifdef MEDIUM
LARGE_CODE = 1
MODEL_NAME EQU <MEDIUM>
endif
ifdef LARGE
LARGE_CODE = 1
LARGE_DATA = 1
MODEL_NAME EQU <LARGE>
endif
ifdef HUGE
LARGE_CODE = 1
LARGE_DATA = 1
MODEL_NAME EQU <HUGE>
endif
.MODEL MODEL_NAME ; Remove this line for MASM 4.0 and earlier.
; Define the size of the return address stored at the top of the stack.
ifdef LARGE_CODE
CODPTRSIZ = 4
else
CODPTRSIZ = 2
endif
; Define the size of any pointer arguments.
ifdef LARGE_DATA
PTRSIZE = 4
else
PTRSIZE = 2
endif
; This next line sets up ARG1 to point at the 1st argument in the stack,
; when it is used in conjunction with BP.
; ( i.e. [BP+ARG1] points to the 1st argument on the stack )
ARG1 = CODPTRSIZ+2
; MACRO MOVARG register, argpos
; ------------
; The following macro will load a word value into a specified register.
; The word value is taken from an argument on the stack.
; The actual argument used is arrived at by adding the specified
; offset (arg) to BP, and using that at a pointer. The predefined value
; ARG1 always points to the first argument on the stack. To access
; subsequent arguments, the size of each of the preceeding arguments
; must be computed, and added to the ARG1 offset.
; [This macro assumes a "push bp" and "mov bp, sp" at the beginning]
;
; Example : In 'C' : func( int x, char *y, int z )
;
; Load 'x' into ax : MOVARG ax, ARG1
; Load 'z' into bx : MOVARG bx, ARG1+2+PTRSIZE
; Load 'y' into es:bx : LDPTR es, bx, ARG1+2
;
; The '2' refers to the size of the 'x' arg, and the PTRSIZE refers
; to the size of the char *y [This is memory-model dependant!]
;
; To load a pointer argument from the stack into a segreg/register pair,
; use the LDPTR macro, described elsewhere.
;
; NOTE: If this macro is used in conjunction with the DEFARGS macro,
; then arguments on the stack can be referred to by name. See the
; example under DEFARGS.
MOVARG macro reg, arg
mov reg, [BP+arg]
ENDM
; MACRO MOVLONG reg1, reg2, arg
; -------------
; Moves the long referred to by "arg" into reg1 and reg2.
; reg1 will contain the high order word, reg2 the low order word.
MOVLONG macro reg1, reg2, arg
mov reg1, [BP+arg+2]
mov reg2, [BP+arg]
ENDM
; MACRO LDPTR segreg, offreg, argpos
; -----------
; This macro is used to load pointer arguments passed on the stack.
; If LARGE_DATA is used, a 4-byte pointer will be loaded into the
; segreg/register pair given. This is done using either the LDS or the
; LES instruction, with the given offset register. Note that this means
; that only the DS or ES segregs may be used.
; If SMALL_DATA is being used, then a 2-byte pointer will be loaded
; from the stack into the specified offset register.
; Additionally, if the segreg is NOT ds, then the ds register will be
; pushed and then popped into the given segreg.
; The argpos parameter is the same as that described in the MOVARG macro.
LDPTR macro seg, reg, arg
ifdef LARGE_DATA
l&seg reg, [BP+arg]
else
ifdif <ds>, <seg>
push ds
pop seg
endif
mov reg, [BP+arg]
endif
ENDM
; MACRO PUSHDS
; ------------
; This macro simply pushes the DS register if LARGE_DATA
;
PUSHDS macro
ifdef LARGE_DATA
push ds
endif
ENDM
; MACRO POPDS
; -----------
; This macro simply pops the DS register if LARGE_DATA
POPDS macro
ifdef LARGE_DATA
pop ds
endif
ENDM
; MACRO STARTPROC name
; --------------------
; Declares the start of a procedure, declaring it as either
; PROC NEAR or PROC FAR, depending on LARGE_CODE being defined.
STARTPROC macro name
ifdef LARGE_CODE
name PROC FAR
else
name PROC NEAR
endif
bp_pushed = FALSE
ENDM
; MACRO DEFARGS name1, type1, name2, type2, ... , name5, type5
; -------------
; This macro should be used just after the STARTPROC macro.
; It first pushes BP, and moves BP with SP.
; Next it defines the names and offsets in the stack (with base BP) of
; up to 5 arguments to be referred to by name inside the procedure.
; Currently, the following argument types are supported :
;
; PTR a data pointer
; CPTR a code pointer
; WORD a word ( or int )
; LONG a double word (A long in 'C')
;
; The macro defines all the names given, and assigns to them the offset
; values to be used with BP in order to access them on the stack.
; The names can then be used as arguments to the LDPTR and MOVARG macros.
; To use them outside these macros, use the [BP+argname] format.
;
; Currently not supported are BYTE and QWORD types.
; (BYTE args are not passed, they are always converted to WORDS by 'C' )
;
; EXAMPLE :
; ---------
; STARTPROC _func ; Start the function
; DEFARGS x, WORD, y, PTR, z, LONG ; Define args
; MOVARG ax, x ; Load AX with x
; LDPTR es:bx, y ; ES:BX now contains Y
; MOVLONG bx, cx, z ; bx contains HI, CX the LO word of z
DEFARGS macro nm1, tp1, nm2, tp2, nm3, tp3, nm4, tp4, nm5, tp5
push bp
mov bp, sp
bp_pushed = TRUE ; Flag this for the RETPROC macro.
ifnb <nm1>
&nm1 = ARG1
endif
ifnb <nm2>
ifidn <tp1>,<PTR>
&nm2 = &nm1+PTRSIZE
endif
ifidn <tp1>,<WORD>
&nm2 = &nm1+2
endif
ifidn <tp1>,<LONG>
&nm2 = &nm1+4
endif
ifidn <tp1>,<CPTR>
&nm2 = &nm1+CODPTRSIZ
endif
endif
ifnb <nm3>
ifidn <tp2>,<PTR>
&nm3 = &nm2+PTRSIZE
endif
ifidn <tp2>,<WORD>
&nm3 = &nm2+2
endif
ifidn <tp2>,<LONG>
&nm3 = &nm2+4
endif
ifidn <tp2>,<CPTR>
&nm3 = &nm2+CODPTRSIZ
endif
endif
ifnb <nm4>
ifidn <tp3>,<PTR>
&nm4 = &nm3+PTRSIZE
endif
ifidn <tp3>,<WORD>
&nm4 = &nm3+2
endif
ifidn <tp3>,<LONG>
&nm4 = &nm3+4
endif
ifidn <tp3>,<CPTR>
&nm4 = &nm3+CODPTRSIZ
endif
endif
ifnb <nm5>
ifidn <tp4>,<PTR>
&nm5 = &nm4+PTRSIZE
endif
ifidn <tp4>,<WORD>
&nm5 = &nm4+2
endif
ifidn <tp4>,<LONG>
&nm5 = &nm4+4
endif
ifidn <tp4>,<CPTR>
&nm5 = &nm4+CODPTRSIZ
endif
endif
ENDM
; MACRO RETPROC
; -------------
; Pops BP if it was pushed (by having called DEFARGS)
; It then returns.
RETPROC macro
if bp_pushed
pop bp
endif
ret
ENDM